package cn.usian.basicInformation.log.commons;


import cn.usian.basicInformation.log.service.ILogService;
import cn.usian.pojo.basicInformation.log.BaseOperationLog;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @path：com.demo.utils.aop.LogAspect.java
 * @className：LogAspect.java
 * @description：切面处理类，操作日志异常日志记录处理
 * @author：tanyp
 * @dateTime：2021/11/18 13:57
 * @editNote：
 */

@Aspect
@Component
@Slf4j
public class LogAspectB {

    ThreadLocal<Long> startTime = new ThreadLocal<>();

    @Autowired
    private ILogService logInfoService;

    ThreadLocal<String> beforeData = new ThreadLocal<>();
    ThreadLocal<String> afterData = new ThreadLocal<>();

    @Pointcut("@annotation(cn.usian.basicInformation.log.commons.Log)")
    // 配置切入点，可多个表达式
    public void logPoinCut() {
    }

    @Pointcut("execution(* cn.usian.*.*.controller..*.*(..))")
    public void exceptionLogPoinCut() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public void postLog(){};

    @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void getLog(){};

    @Before("logPoinCut()")
    public void doBefore(JoinPoint joinPoint) {
        // 接收到请求，记录请求开始时间
        startTime.set(System.currentTimeMillis());

        // 记录操作前的数据
        Object[] args = joinPoint.getArgs();
        beforeData.set(JSON.toJSONString(args));
        log.info("请求参数：" + JSON.toJSONString(args));
    }

    @AfterReturning(value = "logPoinCut()", returning = "keys")
    public void doAfterReturning(JoinPoint joinPoint, Object keys) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) requestAttributes).getRequest();

        BaseOperationLog logInfo = BaseOperationLog.builder().build();

        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();

            // 获取切入点所在的方法
            Method method = signature.getMethod();

            // 获取Log注解上的属性操作
            Log log = method.getAnnotation(Log.class);
            if (Objects.nonNull(log)) {
                logInfo.setOperationModule(log.operationModule());
                logInfo.setOperationType(log.operationType());
            }

            logInfo.setOperationModule(log.operationModule()); // 请求的方法名
            //logInfo.setUpdateId(SecurityUserUtils.getUser().getId()); // 请求用户ID
            logInfo.setOperationType(log.operationType()); // 请求用户名称
            logInfo.setUpdateTime(new Date()); // 创建时间LocalDateTime.now()

            // 记录操作后的数据
            afterData.set(JSON.toJSONString(keys));

            logInfo.setBeforeOperation(beforeData.get());
            logInfo.setAfterOperation(afterData.get());
            System.out.println("获取的logInfo" + logInfo);

            logInfoService.save(logInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Map<String, String> converMap(Map<String, String[]> paramMap) {
        Map<String, String> rtnMap = new HashMap<>();
        for (String key : paramMap.keySet()) {
            rtnMap.put(key, paramMap.get(key)[0]);
        }
        return rtnMap;
    }

    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "<br/>");
        }
        String message = exceptionName + ":" + exceptionMessage + "<br/>" + strbuff.toString();
        return message;
    }
}
